﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AnalysisServices.AdomdClient;
using System.Collections.ObjectModel;
using SQX.DataModel;
using System.Data;
using System.Threading;
using System.Diagnostics;
using System.Windows.Data;
using System.ComponentModel;

namespace SQX.ViewModel
{
    public class CubeViewModel : QueryViewModelBasic
    {
        private string connectionString = "Data Source={0};Initial Catalog={1};Integrated Security=SSPI;Persist Security Info=True;";
        private string server;
        private string cubename;
        private AdomdConnection con;
        private List<AdomdServer> servers = new List<AdomdServer>();
        private string exmessage = "";
        private string baseQuery = "";


        public CubeViewModel(string serverName, string databaseName, string cubeName)
        {
            this.server = serverName;
            con = new AdomdConnection(string.Format(connectionString, serverName, databaseName));
            this.cubename = cubeName;
            base.Markup = new SyntaxMarkup(Service.SourceType.SourceOLAP);
            base.Markup.SetMDXFuncs(con);
            base.modelName = "MDX set, operator: " + Environment.UserDomainName + @"\" + Environment.UserName;
        }

        public CubeViewModel(string serverName, string databaseName, string cubeName, string queryText)
        {
            this.server = serverName;
            con = new AdomdConnection(string.Format(connectionString, serverName, databaseName));
            this.cubename = cubeName;
            base.Markup = new SyntaxMarkup(Service.SourceType.SourceOLAP);
            base.Markup.SetMDXFuncs(con);
            baseQuery = queryText;
            base.modelName = "MDX set, operator: " + Environment.UserDomainName + @"\" + Environment.UserName;
        }

        public Task InitializeModelAsync()
        {
            Task t = new Task(InitializeModel);
            t.Start();
            return t;
        }

        private void InitializeModel()
        {
            try
            {
                con.Open();
                var olapServer = new AdomdServer(this.server);
                servers.Add(olapServer);

                foreach (CubeDef cb in con.Cubes)
                {
                    if (!cb.Name.Contains('$') && cb.Type == CubeType.Cube && cb.Name == this.cubename)
                    {
                        var cube = new AdomdCube(cb);
                        // parse non-measure dimensions
                        foreach (Dimension dim in cb.Dimensions)
                        {
                            if (!dim.UniqueName.Contains("Measures"))
                            {
                                AdomdDimension adim = new AdomdDimension(dim.UniqueName, dim.Caption);
                                foreach (Hierarchy h in dim.Hierarchies)
                                {
                                    AdomdHierarchy adh = new AdomdHierarchy(h.Caption, h.UniqueName);
                                    foreach (Level lv in h.Levels)
                                    {
                                        var memberCollection = lv.GetMembers(0,30); // later make this inherit from settings
                                        AdomdHierarchyAttribute hattr = new AdomdHierarchyAttribute(lv.Caption, lv.UniqueName);
                                        foreach (Member mb in memberCollection)
                                        {
                                            hattr.Members.Add(new AdomdMember(mb.Caption, mb.UniqueName));
                                        }
                                        adh.Attributes.Add(hattr);
                                    }
                                    adim.Hierarchies.Add(adh);
                                }
                                cube.Dimensions.Add(adim);
                            }
                        }

                        // parse measure dimensions
                        AdomdDimension mdim = new AdomdDimension("[Measures]", "Вычисляемые выражения");
                        foreach (Measure cmeasure in cb.Measures)
                        {
                            var dfolder = new AdomdHierarchy(cmeasure.DisplayFolder, cmeasure.DisplayFolder);
                            var dattr = new AdomdHierarchyAttribute(cmeasure.Caption, cmeasure.UniqueName);
                            var found = mdim.Hierarchies.Find(h =>
                                {
                                    return h.ObjectName == dfolder.ObjectName;
                                });
                            if (found != null)
                            {
                                found.Attributes.Add(dattr);
                            }
                            else
                            {
                                dfolder.Attributes.Add(dattr);
                                mdim.Hierarchies.Add(dfolder);
                            }
                        }

                        cube.Dimensions.Add(mdim);
                        // add cube to collection
                        olapServer.Cubes.Add(cube);
                    }
                }

                this.servers.ForEach(srv =>
                    {
                        srv.Cubes.ForEach(cb =>
                            {
                                var elem = new DatabaseElement("[" + cb.ObjectName + "]", "Cube");
                                QueryHelpList.Add(elem);
                                cb.Dimensions.ForEach(dim =>
                                    {
                                        elem = new DatabaseElement(dim.MDXName, dim.ObjectName);
                                        QueryHelpList.Add(elem);
                                        dim.Hierarchies.ForEach(h =>
                                            {
                                                elem = new DatabaseElement(h.MDXPath, h.ObjectName);
                                                QueryHelpList.Add(elem);
                                                h.Attributes.ForEach(attr =>
                                                    {
                                                        elem = new DatabaseElement(attr.MDXPath, attr.ObjectName);
                                                        QueryHelpList.Add(elem);
                                                    });
                                            });
                                    });
                            });
                    });

                Markup.LanguageObjects.ForEach(obj =>
                    {
                        QueryHelpList.Add(obj);
                    });

                var query = new MDXQuery("Query " + Guid.NewGuid().ToString(), baseQuery, con);
                base.activeQuery = query;
                base.QueryCollection.Add(query);
            }
            catch (Exception ex)
            {
                exmessage = ex.Message;
            }
        }

        public List<AdomdServer> Servers { get { return servers; } }

        public string ExceptionMessage { get { return exmessage; } }

    }

    public class AdomdCube : SqxObject
    {
        private List<AdomdDimension> dimensions;

        public AdomdCube(CubeDef cube) : base(cube.Name)
        {
            dimensions = new List<AdomdDimension>();
            base.ObjectCode = cube.Name;
        }

        public List<AdomdDimension> Dimensions { get { return dimensions; } }
    }

    public class AdomdDimension : SqxObject
    {
        private string mdxname;
        private List<AdomdHierarchy> hierarchies;

        public AdomdDimension(string MDXName, string Caption) : base(Caption)
        {
            this.mdxname = MDXName;
            base.ObjectCode = MDXName;
            hierarchies = new List<AdomdHierarchy>();
        }

        public string MDXName { get { return mdxname; } }
        public List<AdomdHierarchy> Hierarchies { get { return hierarchies; } }
    }

    public class AdomdServer : SqxObject
    {
        private List<AdomdCube> cubes;
        
        public AdomdServer(string serverName) : base(serverName)
        {
            cubes = new List<AdomdCube>();
        }

        public List<AdomdCube> Cubes { get { return cubes; } }
    }

    public class AdomdHierarchy : SqxObject
    {
        private string mdxPath;
        private List<AdomdHierarchyAttribute> attributes;

        public AdomdHierarchy(string Name, string path) : base(Name)
        {
            this.mdxPath = path;
            base.ObjectCode = path;
            attributes = new List<AdomdHierarchyAttribute>();
        }

        public List<AdomdHierarchyAttribute> Attributes { get { return attributes; } }
        public string MDXPath { get { return mdxPath; } }
    }

    public class AdomdHierarchyAttribute : SqxObject
    {
        private string mdxPath;
        private List<AdomdMember> members;

        public AdomdHierarchyAttribute(string Name, string path) : base(Name)
        {
            this.mdxPath = path;
            base.ObjectCode = path;
            members = new List<AdomdMember>();
        }

        public List<AdomdMember> Members { get { return members; } }
        public string MDXPath { get { return mdxPath; } }
    }

    public class AdomdMember : SqxObject
    {
        public AdomdMember(string Name, string path) : base(Name)
        {
            base.ObjectCode = path;
        }
    }


    // make this all inherit from SQLObject --> SQX Object
    // this will allow drag-drop to work correctly

}
